from leonardo.cms.models import Page, Category, Comment
from leonardo.wiki04 import WikiFormatter as Wiki04Formatter
from leonardo.wikiBNL.formatter import WikiFormatter as WikiBNLFormatter

from django.shortcuts import render_to_response, get_object_or_404

import time
import random
import md5
from datetime import datetime

def breadcrumbs(path):
    steps = []
    path_so_far = ""
    for step in path.split("/")[:-1]:
        if path_so_far:
            path_so_far += "/" + step
        else:
            path_so_far += step
        try:
            page = Page.objects.get(path=path_so_far)
            if page.page_title:
                title = page.page_title
            else:
                title = step
            steps.append((title, path_so_far))
        except Page.DoesNotExist:
            steps.append((step, path_so_far))
    return steps

def calendar(request):
    return BlogCalendarPart(request).html

def get(path, request, error="INSERT FAILURE"):
    try:
        page = Page.objects.get(path=path)
    except Page.DoesNotExist:
        return error
    return format(page, request)

def display_content(request, path):
    page = get_object_or_404(Page, path=path)
    
    comment_error = None
    author_name = ""
    author_link = ""
    comment_content = ""
    
    if request.method == "POST":
        if request.user.is_authenticated() and page.allow_comments != "NO":
            comment_content = request.POST["comment_content"]
            if comment_content:
                comment = Comment(
                    page = page,
                    comment = comment_content,
                    last_modified = datetime.now(),
                    creation_time = datetime.now(),
                    author = request.user,
                )
                comment.save()
                comment_content = ""
            else:
                comment_error = "No content"
        else:
            if page.allow_comments == "YES":
                author_name = request.POST["author_name"]
                author_link = request.POST["author_link"]
                author_email = request.POST["author_email"]
                comment_content = request.POST["comment_content"]
                if comment_content:
                    verify = request.POST["math_verification"]
                    answer = request.POST["math_answer"]
                    o = md5.new()
                    o.update(answer)
                    if o.hexdigest() == verify:
                        comment = Comment(
                            page = page,
                            comment = comment_content,
                            last_modified = datetime.now(),
                            creation_time = datetime.now(),
                            author_name = author_name,
                            author_link = author_link,
                            author_email = author_email,
                            author_ipaddress = request.META["HTTP_X_FORWARDED_FOR"], # use REMOTE_ADDR if not behind proxy
                        )
                        comment.save()
                        comment_content = ""
                    else:
                        comment_error = "Math question incorrect"
                else:
                    comment_error = "No content"
            else:
                comment_error = "Comments not allowed"
    
    try:
        category = Category.objects.get(term=path)
        category_pages = category.page_set.order_by('creation_time')
        
    except Category.DoesNotExist:
        category = None
        category_pages = []
    
    content = format(page, request)
    
    categories = []
    for c in page.categories.all():
        try:
            next_page = c.page_set.order_by('creation_time').extra(where=["creation_time > '%s'" % page.creation_time])[0]
        except IndexError:
            next_page = None
        try:
            prev_page = c.page_set.order_by('-creation_time').extra(where=["creation_time < '%s'" % page.creation_time])[0]
        except IndexError:
            prev_page = None
        categories.append({
            "category": c,
            "next_page": next_page,
            "prev_page": prev_page,
        })
    
    i,j = random.randint(0, 100), random.randint(0, 10)
    o = md5.new()
    o.update(str(i + j))
    math_verify = o.hexdigest()
    
    blog_entries = Page.objects.filter(path__startswith="blog/").order_by('-creation_time')[:5]
    
    return render_to_response("main.html", {
        "breadcrumbs": breadcrumbs(path),
        "page": page,
        "category": category,
        "category_pages": category_pages,
        "categories": categories,
        "content": content,
        "math_i": i,
        "math_j": j,
        "math_key": math_verify,
        "comment_error": comment_error,
        "author_name": author_name,
        "author_link": author_link,
        "comment_content": comment_content,
        "menu": get("__menu__", request),
        "user": request.user,
        "calendar": calendar(request),
        "blog_entries": blog_entries,
    })

def format(page, request):
    if page.content_type == 'wiki04':
        formatter = Wiki04Formatter()
        content = formatter.format(page.content, lambda x: get(x, request))
    elif page.content_type == 'wikiBNL':
        formatter = WikiBNLFormatter()
        content = formatter.format(page.content, lambda x: get(x, request))
    elif page.content_type == 'xhtml':
        content = page.content
    else:
        content = "unknown content type " + page.content_type
    return content

def blog(request, year=None, month=None, day=None, slug=None):
    if slug:
        return display_content(request, path="blog/%s/%s/%s/%s" % (year, month, day, slug))
    else:
        prefix = "blog/"
        title = "James Tauber's Blog"
        limit = 20
        content = ""
        if year:
            limit = None
            prefix += "%s/" % year
            title += " %s" % year
            if month:
                prefix += "%s/" % month
                title += "/%s" % month
                if day:
                    prefix += "%s" % day
                    title += "/%s" % day
        else:
            content = get("blog", request, error="")
        pages = Page.objects.filter(path__startswith=prefix).order_by('-creation_time')
        if limit:
            pages = pages[:limit]
        entries = []
        for page in pages:
            entry_content = format(page, request)
            if page.allow_comments == "NO":
                show_comment_count = False
            else:
                show_comment_count = True
            entries.append({
                "page_title": page.page_title,
                "author": page.author,
                "content": entry_content,
                "last_modified": page.last_modified,
                "creation_time": page.creation_time,
                "categories": page.categories.all(),
                "path": page.path,
                "show_comment_count": show_comment_count,
                "comment_count": page.comment_set.count()
            })
        blog_entries = Page.objects.filter(path__startswith="blog/").order_by('-creation_time')[:5]
        return render_to_response("blog_list.html", {
            "breadcrumbs": breadcrumbs(prefix.strip("/")),
            "title": title,
            "content": content,
            "entries": entries,
            "menu": get("__menu__", request),
            "user": request.user,
            "calendar": calendar(request),
            "blog_entries": blog_entries,
    })
    


class BlogCalendarPart:
    
    def __init__(self, request):
        path = request.path
        
        # five cases:
        #    /blog/:  - serve up latest month 
        #    /blog/year/ - serve up Jan
        #    /blog/year/month/ - serve up year/month
        #    /blog/year/month/day/ - serve up year/month
        #    anything else - serve up latest month
        
        bl = len("/blog/")
        if path[0:bl] != "/blog/":
            # serve up latest month
            y, m = time.gmtime()[0:2]
        else:
            lookingfor = path[bl:]
            slash = lookingfor.find("/")
            try:
                if slash == -1:
                    y = int(lookingfor)
                    m = 1
                else:
                    y = int(lookingfor[0:4])
                    m = int(lookingfor[5:7])
            except ValueError:
                y, m = time.gmtime()[0:2]
        
        year, last, this, next = self.title_links(y, m)
        
        self.html = HtmlCalendar(y, m, self.day_links(y, m), (last, next), this, year)
    
    def day_links(self,y,m):
        
        # Jump directly down to the month ...
        links = {}
        prefix = "".join(["blog", "/", str(y), "/", "%2.2i" % m])
        for page in Page.objects.filter(path__startswith=prefix):
            day = page.path.split("/")[3]
            links[int(day)] = "/" + prefix + "/" + day
        return links
    
    def title_links(self,y,m):
        
        def yeartitle(y):
            return "".join(["/blog", "/", str(y)])
        
        def increment(y, m, i):
            mm = m + i
            yy = y
            if mm > 12:
                mm, yy = mm % 12, y + mm / 12
            elif mm < 1:
                mm, yy = 12 + mm, y - 1
            return yy, mm
        
        plus = increment(y, m, 1)
        minus = increment(y, m, -1)
        year = yeartitle(y)
        this = "%s%s%2.2i" % (year, "/", m)
        next = "%s%s%2.2i" % (yeartitle(plus[0]), "/", plus[1])
        last = "%s%s%2.2i" % (yeartitle(minus[0]), "/", minus[1])
        return year, last, this, next             


month_names = ["January ", "February ", "March ", "April ", "May ", "June ",
               "July ", "August ", "September ", "October ", "November ", "December "]

def HtmlCalendar(year, month, links={}, arrows=None, monthlink=None, yearlink=None):
    """
    Produces an html table representation of the month. If the links
    argument is passed then it should consist of a set of links keyed by day
    of the month. If the arrows argument is passed, then it should consist of
    a two member tuple which has the links to the previous and next month.
    If the monthlink argument is passed, then it should be used as a link
    from the month title, if the yearlink argument is passed it can be used as
    the yearlink title.
    """
    
    months = ["January ", "February ", "March ", "April ", "May ", "June ",
              "July ", "August ", "September ", "October ", "November ", "December "]
    
    # Ok, I know I should be able to find someone elses code to do this,
    # but it'll take longer to find it than write it
    
    import calendar
    
    def makelink(target, link):
        return "".join(['<a href="',target,'">',link,"</a>"])
    
    def monthtitle(m, link, short=0):
        title = months[m - 1]
        if short:
            title = title[0:3]
        if link is None:
            return title
        else:
            return makelink(link, title)
    
    tr=("<tr>","</tr>")
    td=("""<td align="center">""","</td>")
    
    if yearlink == None:
        yeartitle = str(year)
    else:
        yeartitle = makelink(yearlink, str(year))
    
    if arrows == None:
        template = "".join(["""<table class="blogcal"><tr class="calnav"><td align="center" colspan="7">""",
                          monthtitle(month, monthlink), yeartitle, "</td></tr>"])
    else:
        template = "".join(["""<table class="blogcal"><tr class="calnav">""", td[0], makelink(arrows[0], "&#xAB;"), 
                          td[1], """<td align="center" colspan="5">""",
                          monthtitle(month, monthlink, short=1), " ",
                          yeartitle, "</td>", td[0],
                          makelink(arrows[1], "&#xBB;"), td[1], tr[1]])
    
    template += tr[0]
    for day in ("Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"):
        template += "".join([td[0], day, td[1]])
    
    template += tr[1]
    matrix = calendar.monthcalendar(year, month)
    for week in matrix:
        row = tr[0]
        for day in week:
            if day != 0:
                if day not in links.keys():
                    row += """<td align="center">%s</td>""" % day
                else:
                    row += """<td align="center" class="callink">%s</td>""" % makelink(links[day], str(day))
            else:
                row += "".join(td)
        row += tr[1]
        template += row
    template += "</table>"
    
    return template

